﻿using System;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Threading;
using System.Collections.Generic;

namespace XchangeStreamer.OutputSdk.Internal
{
    internal sealed class Dispatcher : TaskScheduler, IDisposable
    {
        private BlockingCollection<Task> tasks;
        private readonly Thread thread;

        public Dispatcher()
        {
            this.tasks = new BlockingCollection<Task>();

            this.thread = new Thread(() =>
            {
                foreach (var task in this.tasks.GetConsumingEnumerable())
                {
                    TryExecuteTask(task);
                }
            });
            this.thread.IsBackground = true;

            this.thread.SetApartmentState(ApartmentState.STA);

            this.thread.Start();
        }

        protected override void QueueTask(Task task)
        {
            this.tasks.Add(task);
        }

        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return this.tasks.ToArray();
        }

        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            return Thread.CurrentThread.GetApartmentState() == ApartmentState.STA && TryExecuteTask(task);
        }

        public override int MaximumConcurrencyLevel
        {
            get
            {
                return 1;
            }
        }

        public void Dispose()
        {
            if (this.tasks != null)
            {
                this.tasks.CompleteAdding();
                this.thread.Join();

                this.tasks.Dispose();
                this.tasks = null;
            }
        }
    }
}